package edu.vt.ece.rt.quorum;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import edu.vt.ece.rt.dstm.Context;
import edu.vt.ece.rt.dstm.ContextDelegator;
import edu.vt.ece.rt.dstm.QObject;

/*
 * Class Used to save the local objects in JVM
 * @author Sudhanshu
 * TODO: Merge PR & PW in one structure
 */
public class Resource {
	/*
	 * Map to Object Id to Object
	 */
	static ConcurrentHashMap<String, QObject> qObjectMap = new ConcurrentHashMap<String, QObject> ();
	
	/*
	 * Map for Object Id to Object Potential Readers List
	 */
	static ConcurrentHashMap<String, List<Context>> prMap = new ConcurrentHashMap<String, List<Context>> ();		
	
	/*
	 * Map for Object Id to Object Potential Writer List
	 */
	static ConcurrentHashMap<String, List<Context>> pwMap = new ConcurrentHashMap<String, List<Context>> ();
	
	public static QObject getQObject(String Id){
		QObject o = qObjectMap.get(Id);
		return o;
	}
	
	public static QObject putQObject(String Id, QObject qObj){
		return qObjectMap.put(Id, qObj);
	}
	
	public static final List<Context> getPRList(String Id){
		//Fixed Issue on concurrent Update
		List<Context> t= new ArrayList<Context>();
		List<Context> l= prMap.get(Id);
		if(l!=null){
			synchronized(l){
				for(Context c:l){
					t.add(c);
				}
				return t;				
			}
		}
		return null;
	}
	
	public static final List<Context> getPWList(String Id){
		//Fixed Issue on concurrent Update
		List<Context> t= new ArrayList<Context>();
		List<Context> l= pwMap.get(Id);
		if(l!=null){
			synchronized(l){
				for(Context c:l){
					t.add(c);
				}
				return t;				
			}
		}
		return null;
	}
	
	public static void addPR(String Id, Context c){
		List<Context> l;
		if((l=prMap.get(Id))!=null){
			synchronized (l) {
				if(!l.contains(c))			//Add the context to PR only if they already not there
					l.add(c);
			}
			return;
		}
		synchronized (prMap) {
			l = Collections.synchronizedList(new ArrayList<Context>());
			prMap.put(Id, l);			//TODO: Make Sure done atomically, like compareAndSet
			l.add(c);
		}
	}
	
	public static void removePR(String Id, Context c){
		List<Context> l;
		if((l=prMap.get(Id))!=null){
			synchronized (l) {
				l.remove(c);
			}
			return;
		}
	}
	
	public static void addPW(String Id, Context c){
		List<Context> l;
		if((l=pwMap.get(Id))!=null){
			synchronized (l) {
				if(!l.contains(c))				//Same as PR
					l.add(c);
			}
			return;
		}
		synchronized (pwMap) {
			l = Collections.synchronizedList(new ArrayList<Context>());
			pwMap.put(Id, l);			//FIXME: Make Sure done atomically, like compareAndSet
			l.add(c);
		}
	}

	
	public static void removePW(String Id, Context c){
		List<Context> l;
		if((l=pwMap.get(Id))!=null){
			synchronized (l) {
				l.remove(c);
			}
			return;
		}
	}
	
	/**
	 * Removes the transaction from PR and PW of all read-write set objects
	 * @param cxt
	 */
	public static void rmFrLists(Context cxt) {
		//Remove from Readers list
		for(QObject ob: cxt.getReadSet())
			removePR(ob.getId(), ContextDelegator.getContext(cxt.getContextId()));		//Use local copy of context
		
		//Remove for writers list
		for(QObject ob: cxt.getWriteSet())
			removePW(ob.getId(), ContextDelegator.getContext(cxt.getContextId()));
	}
	
	public static void updateObject(String Id, QObject obj){
		qObjectMap.replace(Id, obj);
	}

	/**
	 * Removes the object for node Resource Map atomically
	 * @param obj
	 */
	public static void removeObject(QObject obj) {
		// TODO Auto-generated method stub
		qObjectMap.remove(obj.getId());
	}
	
	
}
